package com.liming.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liming.common.constant.DBConstants;
import com.liming.common.exception.BusinessException;
import com.liming.common.pojo.dto.PageDTO;
import com.liming.common.pojo.dto.product.AddCategoryDTO;
import com.liming.common.pojo.dto.product.UpdateCategoryDTO;
import com.liming.common.pojo.entity.BaseEntity;
import com.liming.common.pojo.entity.product.Category;
import com.liming.common.pojo.vo.PageVO;
import com.liming.common.pojo.vo.product.CategoryTreeVO;
import com.liming.common.pojo.vo.product.CategoryVO;
import com.liming.common.util.BeanUtils;
import com.liming.common.util.PageUtils;
import com.liming.common.util.mybatisplus.MPUtil;
import com.liming.product.enums.SelectedEnum;
import com.liming.product.mapper.CategoryMircoMapper;
import com.liming.product.service.CategoryMircoService;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * @author liming
 * @date 2025/1/15
 */
@Service
public class CategoryMircoServiceImpl extends ServiceImpl<CategoryMircoMapper, Category>
        implements CategoryMircoService, MPUtil<Category> {

    @Override
    public List<CategoryTreeVO> tree() {
        // 放入最低级分类，查询整个分类树
        return getCategoryTree(DBConstants.LEVEL_LEAF, null);
    }

    @NotNull
    private List<CategoryTreeVO> getCategoryTree(Integer level, List<CategoryTreeVO> childrenList) {
        // 查询父级分类
        List<CategoryTreeVO> parentList = lambdaQuery().eq(Category::getLevel, level).list()
                .stream()
                .map(parent -> {
                    CategoryTreeVO vo = new CategoryTreeVO();
                    org.springframework.beans.BeanUtils.copyProperties(parent, vo);
                    if (ObjectUtil.equal(parent.getLevel(), DBConstants.LEVEL_LEAF)) {
                        vo.setChildren(Collections.emptyList());
                        return vo;
                    }
                    vo.setChildren(childrenList.stream()
                            .filter(children -> ObjectUtil.equal(children.getParentId(), parent.getId()))
                            .toList());
                    return vo;
                }).toList();
        // 如果是顶级分类，直接返回
        if (ObjectUtil.equal(parentList.get(0).getLevel(), DBConstants.LEVEL_ROOT)) {
            return parentList;
        }
        // 递归查询父分类
        return getCategoryTree(level - 1, parentList);
    }

    @Override
    public CategoryVO get(Long id) {
        Category category = getById(id);
        Assert.notNull(category, () -> new BusinessException("分类不存在"));
        CategoryVO vo = new CategoryVO();
        org.springframework.beans.BeanUtils.copyProperties(category, vo);
        return vo;
    }

    @Override
    public List<CategoryVO> selectedCategory() {
        return lambdaQuery().eq(Category::getSelected, SelectedEnum.YES.getCode()).list()
                .stream()
                .map(category -> BeanUtils.toBean(category, CategoryVO.class))
                .toList();
    }

    @Override
    public Boolean add(AddCategoryDTO addCategoryDTO) {
        Category save = new Category();
        org.springframework.beans.BeanUtils.copyProperties(addCategoryDTO, save);
        Assert.isTrue(save(save), () -> new BusinessException("分类保存失败"));
        return true;
    }

    @Override
    public Boolean updateCategory(UpdateCategoryDTO updateCategoryDTO) {
        Category update = new Category();
        org.springframework.beans.BeanUtils.copyProperties(updateCategoryDTO, update);
        Assert.isTrue(updateById(update), () -> new BusinessException("分类更新失败"));
        return true;
    }

    @Override
    public Boolean updateSelected(Long id) {
        Category category = getById(id);
        boolean update = lambdaUpdate()
                .eq(Category::getId, id)
                .set(ObjectUtil.equal(category.getSelected(), SelectedEnum.NO.getCode()), Category::getSelected, SelectedEnum.YES.getCode())
                .set(ObjectUtil.equal(category.getSelected(), SelectedEnum.YES.getCode()), Category::getSelected, SelectedEnum.NO.getCode())
                .update();
        Assert.isTrue(update, () -> new BusinessException("分类精选更新失败"));
        return true;
    }

    @Override
    public Collection<Long> parentAndChildren(Long categoryId) {
        if (ObjectUtil.isNull(categoryId)) {
            return Collections.emptyList();
        }
        // 根据传入的分类ID 查询出所有子分类ID
        List<Long> childrenIds = lambdaQuery()
                .eq(Category::getParentId, categoryId)
                .list()
                .stream()
                .map(BaseEntity::getId)
                .toList();
        Collection<Long> result = recursionChildren(childrenIds);
        if (CollUtil.isEmpty(result)) {
            result = new ArrayList<>();
        }
        result.addAll(childrenIds);
        result.add(categoryId);
        return result;
    }

    @Override
    public PageVO<CategoryVO> myPage(PageDTO page) {
        IPage<Category> rawPage = lambdaQuery().page(setPage(page));
        return PageUtils.convert(rawPage, category -> BeanUtils.toBean(category, CategoryVO.class));
    }

    @Override
    public Category getByName(String name) {
        return lambdaQuery().eq(Category::getName, name).one();
    }

    private Collection<Long> recursionChildren(List<Long> parentIds) {
        if (CollUtil.isEmpty(parentIds)) {
            return new ArrayList<>();
        }
        // 根据子分类IDS查询所有子分类
        List<Long> childrenIds = lambdaQuery()
                .in(Category::getParentId, parentIds)
                .list()
                .stream()
                .map(BaseEntity::getId)
                .toList();
        Collection<Long> children2Ids = recursionChildren(childrenIds);
        return new ArrayList<>(CollUtil.addAll(childrenIds, children2Ids));
    }

}
